'use strict';

/**
 * 安全地将对象转换为JSON字符串，处理循环引用
 * @param {Object} obj - 要转换的对象
 * @returns {string} JSON字符串
 */
function safeStringify(obj) {
  const seen = new WeakSet();
  return JSON.stringify(obj, (key, value) => {
    if (typeof value === 'object' && value !== null) {
      if (seen.has(value)) {
        return;
      }
      seen.add(value);
    }
    return value;
  });
}

/**
 * 将下划线格式的键转换为驼峰格式
 * @param {Object|Array} obj - 要转换的对象或数组
 * @returns {Object|Array} 转换后的对象或数组
 */
function toCamelCase(obj) {
  // 非对象或为空直接返回
  if (!obj || typeof obj !== 'object') {
    return obj;
  }

  // 处理日期对象
  if (obj instanceof Date) {
    return obj.toISOString();
  }

  // 处理数组
  if (Array.isArray(obj)) {
    return obj.map(item => toCamelCase(item));
  }

  // 处理Sequelize模型实例
  if (obj.toJSON && typeof obj.toJSON === 'function') {
    obj = obj.toJSON();
  }

  // 处理普通对象
  const result = {};
  for (const key in obj) {
    if (Object.prototype.hasOwnProperty.call(obj, key)) {
      // 将下划线格式转换为驼峰格式
      const camelCaseKey = key.replace(/_([a-z])/g, (match, letter) => letter.toUpperCase());
      result[camelCaseKey] = toCamelCase(obj[key]);
    }
  }
  return result;
}

/**
 * 下划线转驼峰中间件
 */
module.exports = () => {
  return async function camelCaseMiddleware(ctx, next) {
    await next();

    // 只处理成功响应且有数据的情况
    if (ctx.body && ctx.body.code === 200 && ctx.body.data) {
      try {
        // 对于Sequelize模型实例，先调用toJSON()方法
        if (ctx.body.data && typeof ctx.body.data.toJSON === 'function') {
          ctx.body.data = ctx.body.data.toJSON();
        }
        // 应用驼峰转换
        ctx.body.data = toCamelCase(ctx.body.data);
      } catch (error) {
        ctx.logger.error('camelCase middleware error:', error);
        // 出错时尝试使用安全字符串化并解析的方式
        try {
          const jsonStr = safeStringify(ctx.body.data);
          ctx.body.data = toCamelCase(JSON.parse(jsonStr));
        } catch (safeError) {
          ctx.logger.error('Safe camelCase conversion failed:', safeError);
          // 仍然失败则不影响原有数据
        }
      }
    }
  };
};